// --- Copyright (c) 2006-2008 Stefan Kyntchev ---
// This software is written and copyrighted by Stefan Kyntchev 
// and BeyondPod Team members. All rights are reserved.
// Author contact: support@beyondpod.mobi
// ------------------------------------------------------------------------
// This file is part of BeyondPod RSS Feed Reader and Podcast manager
// (www.codeplex.com/BeyondPod) 
// BeyondPod is free software: you can redistribute it and/or modify 
// it under the terms of the GNU General Public License as published by 
// the Free Software Foundation, either version 3 of the License, or 
// (at your option) any later version. 
//  
// BeyondPod is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
// GNU General Public License for more details. 
//  
// You should have received a copy of the GNU General Public License
// along with BeyondPod. If not, see <http://www.gnu.org/licenses/>
// ------------------------------------------------------------------------
// COPYRIGHT NOTICE: This copyright notice may NOT be removed, obscured or modified 
// without written consent from the author.
// --- End copyright notice --- 


using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;
using svs.Mobile.BeyondMedia.FeedCore.Helpers;
using svs.Mobile.BeyondMedia.FeedCore.Properties;
using svs.Mobile.BeyondMedia.FeedCore.RSS.Entities;

namespace svs.Mobile.BeyondMedia.FeedCore.RSS
{
	public class UpdateAndDownloadManager
	{
		#region Delegates

		public delegate void ProcessEvent(int numItems);

		public delegate void UpdateAndDownloadEvent();

		#endregion

		private static readonly FeedList m_DownloadQueue = new FeedList();
		private static readonly ProcessedFeedList m_Statistics = new ProcessedFeedList();
		public static bool m_Processing = false;

		static UpdateAndDownloadManager()
		{
			EnclosureDownloadManager.DownloadBatchCanceled += OnCancel;
			EnclosureDownloadManager.DownloadBatchCompleted += OnDownloadCompleted;
			RssFeedUpdateManager.UpdateCanceled += OnCancel;
			RssFeedUpdateManager.UpdateCompleted += OnUpdateCompleted;
		}

		#region Private Methods

		private static void OnCancel()
		{
			m_DownloadQueue.Clear();
			OnUpdateAndDownloadFinished();
		}

		private static void OnDownloadCompleted()
		{
			m_DownloadQueue.Clear();
			OnUpdateAndDownloadFinished();
		}

		private static void OnUpdateAndDownloadFinished()
		{
			CoreHelper.DumpUpdateStatistics();

			if (UpdateAndDownloadBatchCompleted != null)
				UpdateAndDownloadBatchCompleted();
		}

		private static void OnUpdateCompleted()
		{
			ThreadPool.QueueUserWorkItem(ProcessFeeds);
		}

		private static void ProcessFeeds(object state)
		{
			m_Processing = true;
			m_Statistics.ProcessTime = DateTime.Now;

			List<KeyValuePair<Feed, RssEnclosure>> retVal = new List<KeyValuePair<Feed, RssEnclosure>>();

			if (ProcessingStarted != null)
				ProcessingStarted(m_DownloadQueue.Count);

			int numDownloadable = 0;

			foreach (Feed feed in m_DownloadQueue)
			{
				feed.NumEnclosuresAvailableForDownload = 0;
				feed.NumDownloadedEnclosures = 0;
				feed.DownloadFailed = false;

				if (!feed.IncludeInOneStepDownload || feed.MaxEnclosuresToOneStepDownload == 0)
					continue;

				ProcessStatistics ps = new ProcessStatistics();
				ps.ProcessedFeed = feed;
				m_Statistics.Add(ps);

				numDownloadable++;

				RssFeed rss = null;
				try
				{
					rss = RssFeedCache.LoadFromCache(feed);
				}
				catch (CoreHelper.EncounteredOpmlFeedException)
				{
					feed.Type = FeedType.OPMLFeed;
				}
				catch
				{
					//just continue - we log in LoadFromCache
				}

				if (rss == null)
				{
					continue;
				}

				List<RssEnclosure> enclosures = rss.GetDownloadableEnclosures(feed.MaxEnclosuresToOneStepDownload);
				feed.NumEnclosuresAvailableForDownload = enclosures.Count;

				if (enclosures.Count > 0)
				{
					foreach (RssEnclosure enclosure in enclosures)
					{
						ps.NewEnclosures.Add(enclosure.Url);
						retVal.Add(new KeyValuePair<Feed, RssEnclosure>(feed, enclosure));
					}
				}
				else if (m_Processing == false)
				{
					if (ProcessingCanceled != null)
						ProcessingCanceled(numDownloadable);

					OnCancel();
					return;
				}
			}

			if (retVal.Count > 0)
				EnclosureDownloadManager.DownloadEnclosures(retVal);
			else
			{
				if (ProcessingCompleted != null)
					ProcessingCompleted(numDownloadable);

				OnCancel();
			}

			m_Processing = false;
		}

		#endregion

		#region Public Methods

		public static void StartUpdateDownload(FeedList toDownload)
		{
			if (!CoreHelper.IsDeviceConnected())
			{
				MessageBox.Show(Resources.DeviceNotConnectedMsg, Resources.DeviceNotConnectedTitle,
												MessageBoxButtons.OK,
												MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
				return;
			}

			if (m_DownloadQueue.Count > 0)
			{
				MessageBox.Show(Resources.AnotherDownloadInProgressMsg, Resources.AnotherDownloadInProgressTitle,
				                MessageBoxButtons.OK,
				                MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
				return;
			}

			m_DownloadQueue.AddRange(toDownload);
			RssFeedUpdateManager.UpdateFeeds(m_DownloadQueue);
		}

		/// <summary>
		/// Terminates All updates and Downloads
		/// </summary>
		public static void TerminateAll()
		{
			if (m_Processing)
				m_Processing = false;
			else if (RssFeedUpdateManager.IsUpdating)
				RssFeedUpdateManager.TerminateAllUpdates();
			else if (EnclosureDownloadManager.IsDownloading)
				EnclosureDownloadManager.TerminateAllDownloads();
		}

		#endregion

		#region Public Properties

		/// <summary>
		/// Feed Statistics
		/// </summary>
		public static ProcessedFeedList Statistics
		{
			get { return m_Statistics; }
		}

		/// <summary>
		/// True if the Manager is currently working
		/// </summary>
		public static bool IsWorking
		{
			get { return m_DownloadQueue.Count > 0; }
		}

		#endregion

		public static event ProcessEvent ProcessingStarted;
		public static event ProcessEvent ProcessingCanceled;
		public static event ProcessEvent ProcessingCompleted;

		public static event UpdateAndDownloadEvent UpdateAndDownloadBatchCompleted;
	}
}